/**
 * @author		Sergey Suzdalskiy
 * @e-mail:		sergey.suzdalskiy@gmail.com
 */
package ua.kiev.gcore.net.connections {
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.Socket;
	import flash.net.XMLSocket;
	import flash.system.Security;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import flash.utils.Timer;
	
	import ua.kiev.gcore.logger.Logger;
	import ua.kiev.gcore.net.ServerProxy;
	import ua.kiev.gcore.net.command.Command;
	import ua.kiev.gcore.net.command.IProtocolParser;
	import ua.kiev.gcore.net.connections.event.CommunicateEvent;
	
	public class SocketConnection extends Connection {
		
		private var socket:Socket;
//		private var sendCommandStack:Array;
//		private var receiveCommandStack:Array;
		private var buffer:ByteArray;
		
//		private var tickSendDelay:Number = 100;
//		private var tickReceiveDelay:Number = 100;
		
		private var isClosed:Boolean;
		
		
		
		public function SocketConnection(id:int, ca:ConnectionAttributes, parser:IProtocolParser) {
			
			isClosed = false;
			super(id, ca, parser);
			
//			sendCommandStack = new Array();
//			receiveCommandStack = new Array();
			buffer = new ByteArray();
			buffer.endian = Endian.LITTLE_ENDIAN;
		}
		
		/**
		 * Connect to server
		 */
		override public function init():void {
			socket = new Socket();
			
			socket.addEventListener(Event.CONNECT, connectSuccesfulHandler);
			socket.addEventListener(ProgressEvent.SOCKET_DATA, dataReceivedHandler);
			
			socket.addEventListener(IOErrorEvent.IO_ERROR, socketIoErrorHandler);
			socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityFailedHandler);
			socket.addEventListener(Event.CLOSE, socketCloseHandler);
			
			socket.addEventListener(Event.ACTIVATE, socketActivateHandler);
			socket.addEventListener(Event.DEACTIVATE, socketDeactivateHandler);
			
			try {
				socket.connect(attributes.adress, attributes.port);
			} catch (e:IOError) {
				isClosed = true;
				var connectEvent:CommunicateEvent = new CommunicateEvent(CommunicateEvent.CONNECT_FAILED);
				connectEvent.message = e.message;
				dispatchEvent(connectEvent);
				return;
			}
		}
		
		private function connectSuccesfulHandler(event:Event):void {
			isClosed = false;
			var newEvent:CommunicateEvent = new CommunicateEvent(CommunicateEvent.CONNECT);
			newEvent.message = "connect succesful";
			dispatchEvent(newEvent);
		}
		
		private function dataReceivedHandler(event:ProgressEvent):void {
			var bytes:ByteArray = new ByteArray();
			bytes.endian = Endian.LITTLE_ENDIAN;
			socket.readBytes(bytes);
			if(listener){
				listener.parse(bytes);
			}
			socket.flush();
		}
		
		private function socketIoErrorHandler(event:IOErrorEvent):void {
			if(!isClosed){
				isClosed = true;
				var newEvent:CommunicateEvent = new CommunicateEvent(CommunicateEvent.CONNECT_FAILED);
				newEvent.message = event.text;
				dispatchEvent(newEvent);
			}
			
		}
		
		private function onSecurityFailedHandler(event:SecurityErrorEvent):void {
			if(!isClosed){
				isClosed = true;
				var newEvent:CommunicateEvent = new CommunicateEvent(CommunicateEvent.CONNECT_FAILED);
				newEvent.message = event.text;
				dispatchEvent(newEvent);
			}
		}
		
		private function socketCloseHandler(event:Event):void {
			if(!isClosed){
				isClosed = true;
				var newEvent:CommunicateEvent = new CommunicateEvent(CommunicateEvent.CONNECT_FAILED);
				newEvent.message = event.toString();
				dispatchEvent(newEvent);
			}
		}
		
		private function socketActivateHandler(event:Event):void {
			
		}
		
		private function socketDeactivateHandler(event:Event):void {
			
		}
		
		private function disconnect():void {
			isClosed = true;
			if (socket.connected) {
				socket.close();
			}
		}
		
		override public function sendCommand(command:Command):void {
			send(command);
		}
		
		
		
		
		private function send(command:Command):void {
			try {
				if(command.type == Command.STRING){
					socket.writeUTFBytes(command.data as String);					
					socket.flush();
				}
				if(command.type == Command.BYTEARRAY){					
					socket.writeBytes(command.data as ByteArray);					
					socket.flush();
				}				
			} catch(e:Error) {
				Logger.ERROR("socket.write Error: " + e.message);
			}
		}
		
		override public function destroy():void {
			socket.removeEventListener(Event.CONNECT, connectSuccesfulHandler);
			socket.removeEventListener(ProgressEvent.SOCKET_DATA, dataReceivedHandler);
			
			socket.removeEventListener(IOErrorEvent.IO_ERROR, socketIoErrorHandler);
			socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityFailedHandler);
			socket.removeEventListener(Event.CLOSE, socketCloseHandler);
			if (socket.connected) {
				socket.close();
			}
			socket = null;
		}
	}
}